package org.jeecg.common;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.jeecg.common.util.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.validation.constraints.NotNull;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @author DK
 * @version 1.0
 * @date 2020/12/3 14:24
 **/
@Component
@Slf4j
public class MessageSNUtil {
    private MessageSNUtil(){

    }
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private static MessageSNUtil messageSNUtil;

    @PostConstruct
    public void init() {
        messageSNUtil = this;
        messageSNUtil.stringRedisTemplate = this.stringRedisTemplate;
    }

    /**
     * 漏洞报告编号
     */
    private static final String VUL_REPORT = "VUL";

    /**
     * 防守报告编号
     */
    private static final String DEF_REPORT = "DEF";

    /**
     * 人员管理导入编号
     */
    private static final String WORK_NO = "WORK_NO";

    /**
     * 攻防任务编号
     */
    private static final String OFFENSIVE_DEFENSIVE_TASK = "DEF_TASK";

    /**
     * 用户认证审核表编号
     */
    private static final String USER_AUDIT = "AUDIT";

    /**
     * 用户认证审核表编号
     */
    private static final String TASKNO = "TASKNO";
    /**
     * 文件编号
     **/
    private static final String FILE = "FILE";

    private static final DateTimeFormatter FMT = DateTimeFormatter.ofPattern("yyyyMMdd");

    /**
     * 时间格式(yyyyMMddHHmmss)
     */
    private static final String DAY_TIME_NUMBER_PATTERN = "yyyyMMdd";

    private static final PrimaryGenerate FILE_INTEGER = new PrimaryGenerate(FILE);


    private static final long MOULD_TAKING_NUM = 100_000_000L -1;
    private static final long MOULD_TAKING_NUM6 = 100_000_0L -1;
    private static final long MOULD_TAKING_NUM4 = 100_00L - 1 ;

    private static SecureRandom sRandom;
    static {
        try {
            String OS = System.getProperty("os.name").toLowerCase();
            if (OS.indexOf("windows") > -1) {
                sRandom = SecureRandom.getInstance("SHA1PRNG");
                // 随机数生成采用SHA1PRNG
            } else {
                sRandom = SecureRandom.getInstance("NativePRNGNonBlocking");
                // 随机数生成采用NativePRNGNonBlocking
            }
        } catch (NoSuchAlgorithmException var1) {
            throw new RuntimeException("创建securityRandom失败", var1);
        }
    }

    /**
     * 文件编号
     */
    public static String generateFileMessageSN() {
        return FILE + DateUtils.formatDate(new Date(), DAY_TIME_NUMBER_PATTERN) + generateDigitSerialNumber6(FILE_INTEGER);
    }

    /**
     * YYYYMMDD+6位流水号，6位流水号每日零时从1开始计数，如果当日计数溢出，再次从1开始循环计数。
     */
    public static String generateDigitSerialNumber6(@NotNull PrimaryGenerate primaryGenerate) {
        return primaryGenerate.generateDigitSerialNumber6();
    }

    @Data
    private static class PrimaryGenerate {
        private String key;
        PrimaryGenerate(String key){
            this.key = key;
        }

        public String generateDigitSerialNumber(){
            //时间戳
            String datetime = new SimpleDateFormat("yyyyMMdd").format(new Date());
            //Redis key的前缀
            String redisKey = MessageFormat.format("{0}:{1}", key, datetime);
            //查询key是否存在，不存在返回1，存在的话则自增加1
            Long autoId = messageSNUtil.stringRedisTemplate.opsForValue().increment(redisKey, 1);
            //设置key过期时间, 保证每天的流水号从1开始
            if(autoId == 1){
                Long endTime = getEndTime();
                messageSNUtil.stringRedisTemplate.expire(redisKey, endTime, TimeUnit.MILLISECONDS);
            }
            long num =  autoId % MOULD_TAKING_NUM;
            if(num == 0L){
                autoId =  messageSNUtil.stringRedisTemplate.opsForValue().increment(redisKey, 1);
                num = autoId % MOULD_TAKING_NUM;
            }
            return String.format("%08d", num);
        }

        public String generateDigitSerialNumber6(){
            //时间戳
            String datetime = new SimpleDateFormat("yyyyMMdd").format(new Date());
            //Redis key的前缀
            String redisKey = MessageFormat.format("{0}:{1}", key, datetime);
            //查询key是否存在，不存在返回1，存在的话则自增加1
            Long autoId = messageSNUtil.stringRedisTemplate.opsForValue().increment(redisKey, 1);
            //设置key过期时间, 保证每天的流水号从1开始
            if(autoId == 1){
                Long endTime = getEndTime();
                messageSNUtil.stringRedisTemplate.expire(redisKey, endTime, TimeUnit.MILLISECONDS);
            }
            long num =  autoId % MOULD_TAKING_NUM6;
            if(num == 0L){
                autoId =  messageSNUtil.stringRedisTemplate.opsForValue().increment(redisKey, 1);
                num = autoId % MOULD_TAKING_NUM6;
            }
            return String.format("%06d", num);
        }



        public String generateDigitSerialNumberFour() {
            return this.generateDigitSerialNumber(MOULD_TAKING_NUM4, "%04d");
        }

        public String generateDigitSerialNumber(long mouldTakingNum, String format) {
            //时间戳
            String datetime = new SimpleDateFormat("yyyyMMdd").format(new Date());
            //Redis key的前缀
            String redisKey = MessageFormat.format("{0}:{1}", key, datetime);
            //查询key是否存在，不存在返回1，存在的话则自增加1
            Long autoId = messageSNUtil.stringRedisTemplate.opsForValue().increment(redisKey, 1);
            //设置key过期时间, 保证每天的流水号从1开始
            if(autoId == 1){
                Long endTime = getEndTime();
                messageSNUtil.stringRedisTemplate.expire(redisKey, endTime, TimeUnit.MILLISECONDS);
            }
            long num =  autoId % mouldTakingNum;
            if(num == 0L){
                autoId =  messageSNUtil.stringRedisTemplate.opsForValue().increment(redisKey, 1);
                num = autoId % mouldTakingNum;
            }
            return String.format(format, num);
        }

        /**
         * 获取到当天结束还有多少毫秒
         * @return
         */
        private static Long getEndTime() {
            return -Duration.between(LocalDateTime.of(LocalDate.now(), LocalTime.MAX), LocalDateTime.now()).toMillis();
        }
    }

    public static String random(int length) {
        StringBuilder stringBuilder = new StringBuilder();

        for(int i = 0; i < length; ++i) {
            stringBuilder.append(sRandom.nextInt(10));
        }

        return stringBuilder.toString();
    }

    public static String generateRandomCode() {
        return random(6);
    }

    /**
     * 生成随机码（含数字和字母）
     *
     * @param length 长度
     * @return
     */
    public static String generateRandomName(int length) {
        return RandomStringUtils.randomAlphanumeric(length);
    }

    /**
     * 生成随机数字
     *
     * @param length
     * @return
     */
    public static String generateRandomNumber(int length) {
        return RandomStringUtils.randomNumeric(length);
    }




}
